﻿using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Text.RegularExpressions;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

using System.IO;


using Common;

namespace com.globalwave.common
{
    /*
     在方法体外增加下边的函数
//2009-07-13 杨鑫增加 用于取回 ckfinder 返回的图片地址并对路径文本框和预览图片进行赋值 
function SetFileField(fileUrl) 
{
   //获取主Div下的所有文本框控件
    var inputStr = document.getElementById("cke_txtContent_dialog").getElementsByTagName("Input");
    for(var i=0; i<inputStr.length; i++)
    {
        if(inputStr[i].type=="text")
        {
            //第一个输入框控件是图像路径，得到ID，设置新的图片路径
            CKEDITOR.document.getById(inputStr[i].id).setValue(fileUrl);
            break ;
        }
    }
    CKEDITOR.document.getById('previewImage').setAttribute('src', decodeURI(fileUrl));
}

     */
    public partial class UploadPage : Common.BasePage
    {
        protected DataSet messageDS = null;

        private const string DEFAULT_USER_FILES_PATH = "/uploadfiles/";
        private static IDictionary<string, bool> resourceTypes = new Dictionary<string, bool>();
        private static IDictionary<string, bool> fileAllowedExtensions = new Dictionary<string, bool>();
        private static IDictionary<string, bool> imageAllowedExtensions = new Dictionary<string, bool>();
        private static IDictionary<string, bool> flashAllowedExtensions = new Dictionary<string, bool>();
        private static IDictionary<string, bool> mediaAllowedExtensions = new Dictionary<string, bool>();
        private static IDictionary<string, bool> htmlExtensions = new Dictionary<string, bool>();

        static UploadPage()
        {
            put(resourceTypes, new string[] { "file", "image", "flash", "media" });
            put(fileAllowedExtensions, new string[] { "7z", "aiff", "asf", "avi", "bmp", "csv", "doc", "fla", "flv", "gif", "gz", "gzip", "jpeg", "jpg", "mid", "mov", "mp3", "mp4", "mpc", "mpeg", "mpg", "ods", "odt", "pdf", "png", "ppt", "pxd", "qt", "ram", "rar", "rm", "rmi", "rmvb", "rtf", "sdc", "sitd", "swf", "sxc", "sxw", "tar", "tgz", "tif", "tiff", "txt", "vsd", "wav", "wma", "wmv", "xls", "xml", "zip" });
            put(imageAllowedExtensions, new string[] { "bmp", "gif", "jpeg", "jpg", "png" });
            put(flashAllowedExtensions, new string[] { "swf", "flv" });
            put(mediaAllowedExtensions, new string[] { "aiff", "asf", "avi", "bmp", "fla", "flv", "gif", "jpeg", "jpg", "mid", "mov", "mp3", "mp4", "mpc", "mpeg", "mpg", "png", "qt", "ram", "rm", "rmi", "rmvb", "swf", "tif", "tiff", "wav", "wma", "wmv" });
            put(htmlExtensions, new string[] { "html", "htm", "xml", "xsd", "txt", "js" });
        }

        public static void put(IDictionary<string, bool> dict, string[] values) {
            foreach (string v in values) {
                dict[v] = true;
            }
        }

        public void create() {

            string sResourceType = Request.QueryString["Type"];

            if (sResourceType == null)
            {
                this.SendFileUploadResponse(1, true, "", "", "Invalid request.");
                return;
            }

            // Check if it is an allowed type.
            sResourceType = sResourceType.ToLower();

            if (!resourceTypes.ContainsKey(sResourceType))
            {
                this.SendFileUploadResponse(1, true, "", "", "Invalid resource type specified.");
                return;
            }

            this.FileUpload(sResourceType, "/", true);

        }

        protected void FileUpload(string resourceType, string currentFolder, bool isQuickUpload)
        {
            HttpPostedFile oFile = Request.Files[0];

            string sFileName = "";

            if (oFile == null)
            {
                this.SendFileUploadResponse(202, isQuickUpload);
                return;
            }


            // Get the uploaded file name.
            sFileName = System.IO.Path.GetFileName(oFile.FileName);
            sFileName = this.SanitizeFileName(sFileName);

            string sExtension = System.IO.Path.GetExtension(oFile.FileName);
            sExtension = sExtension.TrimStart('.');

            if ("file".Equals(resourceType) && !fileAllowedExtensions.ContainsKey(sExtension)
                || "image".Equals(resourceType) && !imageAllowedExtensions.ContainsKey(sExtension)
                || "flash".Equals(resourceType) && !flashAllowedExtensions.ContainsKey(sExtension)
                || "media".Equals(resourceType) && !mediaAllowedExtensions.ContainsKey(sExtension))
            {
                this.SendFileUploadResponse(202, isQuickUpload);
                return;
            }

            if (htmlExtensions.ContainsKey(sExtension) && !this.CheckNonHtmlFile(oFile))
            {
                this.SendFileUploadResponse(202, isQuickUpload);
                return;
            }

            int iErrorNumber = 0;
            int iCounter = 0;

            // Map the virtual path to the local server path.
            string sServerDir = this.getFolderPath(resourceType, isQuickUpload);
            while (true)
            {
                string sFilePath = System.IO.Path.Combine(Server.MapPath(sServerDir), sFileName);

                if (System.IO.File.Exists(sFilePath))
                {
                    iCounter++;
                    sFileName =
                        System.IO.Path.GetFileNameWithoutExtension(oFile.FileName) +
                        "(" + iCounter + ")." +
                        sExtension;

                    iErrorNumber = 201;
                }
                else
                {
                    oFile.SaveAs(sFilePath);
                    break;
                }
            }

            string sFileUrl = sServerDir + sFileName;

            this.SendFileUploadResponse(iErrorNumber, isQuickUpload, sFileUrl, sFileName);
        }

        private void SendFileUploadResponse(int errorNumber, bool isQuickUpload)
        {
            this.SendFileUploadResponse(errorNumber, isQuickUpload, "", "", "");
        }

        private void SendFileUploadResponse(int errorNumber, bool isQuickUpload, string fileUrl, string fileName)
        {
            this.SendFileUploadResponse(errorNumber, isQuickUpload, fileUrl, fileName, "");
        }

        protected void SendFileUploadResponse(int errorNumber, bool isQuickUpload, string fileUrl, string fileName, string customMsg)
        {
            Response.Clear();

            Response.Write("<script type=\"text/javascript\">");

            // Minified version of the document.domain automatic fix script.
            // The original script can be found at _dev/domain_fix_template.js
            //
            //Response.Write(@"(function(){var d=document.domain;while (true){try{var A=window.top.opener.document.domain;break;}catch(e) {};d=d.replace(/.*?(?:\.|$)/,'');if (d.length==0) break;try{document.domain=d;}catch (e){break;}}})();");

            if (isQuickUpload)
                Response.Write("window.parent.setURL(" + errorNumber + ",'" + fileUrl.Replace("'", "\\'") + "','" + fileName.Replace("'", "\\'") + "','" + customMsg.Replace("'", "\\'") + "') ;");
                //Response.Write("window.parent.OnUploadCompleted(" + errorNumber + ",'" + fileUrl.Replace("'", "\\'") + "','" + fileName.Replace("'", "\\'") + "','" + customMsg.Replace("'", "\\'") + "') ;");
            else
                Response.Write("window.parent.frames['frmUpload'].OnUploadCompleted(" + errorNumber + ",'" + fileName.Replace("'", "\\'") + "') ;");

            Response.Write("</script>");

            //Response.End();
            Response.Flush();
        }

        protected string getFolderPath(string resourceType, bool isQuickUpload)
        {
            
            // Get the resource type directory.
            string sResourceTypePath = DEFAULT_USER_FILES_PATH ;
            
            if (isQuickUpload) {
                sResourceTypePath += "/temp" ;
            } else {
                sResourceTypePath += "/" + resourceType ;
            }

            string dir = Server.MapPath(sResourceTypePath);

            // Ensure that the directory exists.
            if (!System.IO.Directory.Exists(dir)) System.IO.Directory.CreateDirectory(dir);

            // Return the resource type directory combined with the required path.
            return sResourceTypePath + "/";
        }


        // Do a cleanup of the folder name to avoid possible problems
        protected string SanitizeFolderName(string folderName)
        {
            // Remove . \ / | : ? * " < >
            return Regex.Replace(folderName, @"[.\\/|:?*""<>\p{C}]", "_", RegexOptions.None);
        }

        // Do a cleanup of the file name to avoid possible problems
        private string SanitizeFileName(string fileName)
        {
            // Replace dots in the name with underscores (only one dot can be there... security issue).
            //if (Config.ForceSingleExtension)
                fileName = Regex.Replace(fileName, @"\.(?![^.]*$)", "_", RegexOptions.None);

            // Remove \ / | : ? * " < >
            return Regex.Replace(fileName, @"[\\/|:?*""<>\p{C}]", "_", RegexOptions.None);
        }

        private bool CheckNonHtmlFile(HttpPostedFile file)
        {
            byte[] buffer = new byte[1024];
            file.InputStream.Read(buffer, 0, 1024);

            string firstKB = System.Text.ASCIIEncoding.ASCII.GetString(buffer);

            if (Regex.IsMatch(firstKB, @"<!DOCTYPE\W*X?HTML", RegexOptions.IgnoreCase | RegexOptions.Singleline))
                return false;

            if (Regex.IsMatch(firstKB, @"<(?:body|head|html|img|pre|script|table|title)", RegexOptions.IgnoreCase | RegexOptions.Singleline))
                return false;

            //type = javascript
            if (Regex.IsMatch(firstKB, @"type\s*=\s*[\'""]?\s*(?:\w*/)?(?:ecma|java)", RegexOptions.IgnoreCase | RegexOptions.Singleline))
                return false;

            //href = javascript
            //src = javascript
            //data = javascript
            if (Regex.IsMatch(firstKB, @"(?:href|src|data)\s*=\s*[\'""]?\s*(?:ecma|java)script:", RegexOptions.IgnoreCase | RegexOptions.Singleline))
                return false;

            //url(javascript
            if (Regex.IsMatch(firstKB, @"url\s*\(\s*[\'""]?\s*(?:ecma|java)script:", RegexOptions.IgnoreCase | RegexOptions.Singleline))
                return false;

            return true;
        }
    }
}
